<template>
    <canvas class="canvas" ref="canvas" @click="addStar" @mousemove="mouseMove" @mouseleave="mouseX = null"></canvas>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from "vue";

const canvas = ref<HTMLCanvasElement>();
let ctx: CanvasRenderingContext2D = null;
// 星星数组
let starList: Star[] = [];
// 动画定时器
let animationTimer = 0;
// 鼠标在canvas上的坐标
let mouseX = null;
let mouseY = null;

// 初始化
onMounted(() => {
    ctx = canvas.value.getContext("2d");
    canvas.value.width = canvas.value.clientWidth;
    canvas.value.height = canvas.value.clientHeight;
    // 创建100个星星
    for (let i = 0; i < 100; i++) {
        let x = Math.random() * canvas.value.width;
        let y = Math.random() * canvas.value.height;
        starList.push(new Star(x, y));
    }
    animation();
});
// 动画
function animation() {
    animationTimer = requestAnimationFrame(() => {
        // 清空画板
        ctx.clearRect(0, 0, canvas.value.width, canvas.value.height);
        ctx.fillStyle = "#ffffff";
        ctx.strokeStyle = "#ffffff77";
        // 移动并绘制星星
        starList.forEach((star) => {
            star.move();
            star.draw();
        });
        starList.forEach((star, index) => {
            // 遍历剩下的星星，比较和当前星星的距离
            for (let i = index + 1; i < starList.length; i++) {
                let { x: otherX, y: otherY } = starList[i];
                // 横纵坐标都在50距离内，连线
                if (Math.abs(star.x - otherX) < 50 && Math.abs(star.y - otherY) < 50) {
                    drawLine(star.x, star.y, otherX, otherY);
                }
            }
            // 与鼠标连线判断
            if (mouseX != null && Math.abs(mouseX - star.x) < 50 && Math.abs(mouseY - star.y) < 50) {
                drawLine(star.x, star.y, mouseX, mouseY);
                star.isCaptured = true;
            } else {
                star.isCaptured = false;
            }
        });
        animation();
    });
}

function mouseMove(e: MouseEvent) {
    mouseX = e.offsetX;
    mouseY = e.offsetY;
}

function addStar(e: MouseEvent) {
    for (let i = 0; i < 5; i++) {
        starList.push(new Star(e.offsetX, e.offsetY));
    }
}
// 星星类
class Star {
    x: number;
    y: number;
    // 随机半径
    r = 2 + Math.random() * 2;
    // 随机速度
    speedX = (Math.random() > 0.5 ? 1 : -1) * Math.random() * 0.5;
    speedY = (Math.random() > 0.5 ? 1 : -1) * Math.random() * 0.5;
    // 是否被鼠标捕获
    isCaptured = false;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
    // 绘制星星
    draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
        ctx.fill();
        ctx.closePath();
    }
    // 移动星星
    move() {
        this.x += this.speedX;
        this.y += this.speedY;
        // 默认边界
        let top = 0;
        let bottom = canvas.value.height;
        let left = 0;
        let right = canvas.value.width;
        // 当被鼠标捕获的边界
        if (this.isCaptured) {
            top = mouseY - 50;
            bottom = mouseY + 50;
            left = mouseX - 50;
            right = mouseX + 50;
        }
        // 碰到边界时，反弹，只需要把speed取反就行
        if (this.x <= left || this.x >= right) {
            this.speedX *= -1;
        }
        if (this.y <= top || this.y >= bottom) {
            this.speedY *= -1;
        }
    }
}
// 连线
function drawLine(startX: number, startY: number, endX: number, endY: number) {
    ctx.beginPath();
    ctx.moveTo(startX, startY);
    ctx.lineTo(endX, endY);
    ctx.stroke();
    ctx.closePath();
}

// 窗口大小变化事件
function windowResize() {
    canvas.value.width = canvas.value.clientWidth;
    canvas.value.height = canvas.value.clientHeight;
}
window.addEventListener("resize", windowResize);

onUnmounted(() => {
    window.removeEventListener("resize", windowResize);
    cancelAnimationFrame(animationTimer);
});
</script>
<style lang="scss" scoped src="./starry.scss"></style>
